#include <stdio.h>
#include <stdlib.h>
#include "calculator.h"

//获取运算符优先级
static int get_pri(datatype op)
{
	switch (op)
	{
	case '(':
		return 0;
	case '+':
	case '-':
		return 1;
	case '*':
	case '/':
		return 2;
	default:
		fprintf(stderr, "get_pri() get error operator:'%c'\n", op);
		exit(EXIT_FAILURE);
	}
}

//计算
void compute(sqstack *num, datatype *op)
{
	datatype n1, n2, n;

	stack_pop(num, &n2);   //先出来右操作数
	stack_pop(num, &n1);   //后出来左操作数

	switch (*op)
	{
	case '+':
		n = n1 + n2;
		break;
	case '-':
		n = n1 - n2;
		break;
	case '*':
		n = n1 * n2;
		break;
	case '/':
		n = n1 / n2;
		break;
	default:
		fprintf(stderr, "compute() get error operator:'%c'\n", *op);
		exit(EXIT_FAILURE);
	}
	stack_push(num, &n);
}

//处理')'
void deal_bracket(sqstack *num, sqstack *op)
{
	datatype old_op;

	stack_pop(op, &old_op);
	while (old_op != '(') //栈顶元素不为'('就计算
	{
		compute(num, &old_op);
		stack_pop(op, &old_op);
	}
}

//处理运算符：+ - * / (
void deal_op(sqstack *num, sqstack *op, int oper)
{
	datatype old_op;

	if (stack_isempty(op) || oper == '(') //栈为空或当前运算符为'(',直接入栈
	{
		stack_push(op, &oper);
		return;
	}

	stack_top(op, &old_op); //获取栈顶运算符

	while (get_pri(oper) <= get_pri(old_op)) //当前运算符比栈顶运算符优先级低
	{
		stack_pop(op, &old_op); //栈顶运算符出栈计算
		compute(num, &old_op);

		if (stack_isempty(op)) //判断栈是否为空,栈为空表示当前运算符可直接入栈
			break;   
		stack_top(op, &old_op); //获取新的栈顶运算符
	}
	stack_push(op, &oper); // while循环结束后,运算符优先级比栈顶运算符高或者栈为空,运算符入栈
}

datatype calculator(sqstack *num, sqstack *op, char *str)
{
	int i = 0, value = 0, flag = 0;
	datatype old_op;

	while (str[i])
	{
		//是操作数的情况
		if (str[i] >= '0' && str[i] <= '9')
		{
			value = value * 10 + str[i] - '0';
			flag = 1;
		}
		else //运算符的情况
		{
			if (flag == 1) //检测到运算符，(flag == 1)表示前一个是处理的是操作数,但操作数还未入栈，需要入栈
			{
				stack_push(num, &value); //数值入栈
				flag = value = 0;	 //标志位置为0,value置为0
			}

			if (str[i] == ')') //右括号单独处理
				deal_bracket(num, op);
			else //运算符: ( + - * /
				deal_op(num, op, str[i]);
		}
		++i;
	}

	if (flag)    //表达式最后一项为操作数，需要入栈
		stack_push(num, &value);

	//表达式已处理完，计算栈中剩余操作数
	while (!stack_isempty(op))
	{
		stack_pop(op, &old_op);
		compute(num, &old_op);
	}

	stack_pop(num, &value);

	return value;
}